`include "mycpu.h"

module id_stage(
    input                          clk           ,
    input                          reset         ,
    input                          flush         ,
    //allowin
    input                          es_allowin    ,
    output                         ds_allowin    ,
    //from fs
    input                          fs_to_ds_valid,
    input  [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus  ,
    //from es
    input                          es_to_ds_valid,
    input  [`ES_TO_DS_BUS_WD -1:0] es_to_ds_bus  ,
    //from ms
    input                          ms_to_ds_valid,
    input  [`MS_TO_DS_BUS_WD -1:0] ms_to_ds_bus  ,
    //to es
    output                         ds_to_es_valid,
    output [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus  ,
    //to fs
    output [`BR_BUS_WD       -1:0] br_bus        ,
    //to rf: for write back
    input  [`WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus ,
    input  interrupt
);

wire   [31:0]ms_rf_we_ex;
wire   [31:0]rf_we_ex;

reg         ds_valid   ;
wire        ds_ready_go;

wire [31                 :0] fs_pc;
reg  [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus_r;
assign fs_pc = fs_to_ds_bus[31:0];

wire fs_ex;
wire [31:0] ds_inst;
wire [31:0] ds_pc  ;
wire [31:0] ds_pc_add_4;
wire [31:0] fs_badvaddr;
wire   [4:0]fs_excode;
wire ds_tlb_r;

assign {ds_refetch,
        ds_tlb_r,
        fs_excode,
        fs_badvaddr,
        fs_ex,
        ds_inst,
        ds_pc  } = fs_to_ds_bus_r;

wire [ 3:0] rf_we   ;
wire [ 4:0] rf_waddr;
wire [31:0] rf_wdata;
wire        ws_inst_mfc0;
assign {ws_inst_mfc0,//41:41
        rf_we   ,  //40:37
        rf_waddr,  //36:32
        rf_wdata   //31:0
       } = ws_to_rf_bus;

wire [ 4:0] es_dest;
wire [31:0] es_alu_result;
wire        es_load_op;
wire        es_inst_mfc0;
assign {es_inst_mfc0   ,  //38:38
        es_load_op     ,  //37:37
        es_dest        ,  //36:32
        es_alu_result    //31:0
         }= es_to_ds_bus;

wire [ 4:0] ms_dest;
wire        ms_res_from_mem;
wire [31:0] ms_final_result;
wire [ 3:0] ms_rf_we;
wire ms_ready_go;
wire ms_inst_mfc0;
assign {ms_ready_go   ,   //43:43
        ms_inst_mfc0   ,  //42:42
        ms_rf_we      ,   //41:38
        ms_res_from_mem,  //37:37
        ms_dest        ,  //36:32
        ms_final_result    //31:0
         }= ms_to_ds_bus;

wire        br_stall;
wire        br_taken;
wire [31:0] br_target;

wire [11:0] alu_op;
wire        load_op;
wire        src1_is_sa;
wire        src1_is_pc;
wire        src1_is_0;
wire        src2_is_imm;
wire        src2_is_0imm;
wire        src2_is_8;
wire        res_from_mem;
wire        gr_we;
wire        mem_we;
wire        load_sign; 
wire        load_byte;
wire        load_hw;
wire        store_byte;
wire        store_hw;
wire [ 4:0] dest;
wire [15:0] imm;
reg  [31:0] rs_value;
reg  [31:0] rt_value;

wire [ 5:0] op;
wire [ 4:0] rs;
wire rs_valid;
wire [ 4:0] rt;
wire rt_valid;
wire [ 4:0] rd;
wire [ 4:0] sa;
wire [ 5:0] func;
wire [25:0] jidx;
wire [63:0] op_d;
wire [31:0] rs_d;
wire [31:0] rt_d;
wire [31:0] rd_d;
wire [31:0] sa_d;
wire [63:0] func_d;

wire        no_inst;

wire        inst_addu;
wire        inst_subu;
wire        inst_slt;
wire        inst_sltu;
wire        inst_and;
wire        inst_or;
wire        inst_xor;
wire        inst_nor;
wire        inst_sll;
wire        inst_srl;
wire        inst_sra;
wire        inst_addiu;
wire        inst_lui;
wire        inst_lw;
wire        inst_sw;
wire        inst_beq;
wire        inst_bne;
wire        inst_jal;
wire        inst_jr;

wire        inst_add;
wire        inst_addi;
wire        inst_sub;
wire        inst_slti;
wire        inst_sltiu;
wire        inst_andi;
wire        inst_ori;
wire        inst_xori;
wire        inst_sllv;
wire        inst_srlv;
wire        inst_srav;

wire        inst_mult;
wire        inst_multu;
wire        inst_div;
wire        inst_divu;
wire        inst_mfhi;
wire        inst_mflo;
wire        inst_mthi;
wire        inst_mtlo;

wire        inst_bgez;
wire        inst_bgtz;
wire        inst_blez;
wire        inst_bltz;
wire        inst_bltzal;
wire        inst_bgezal;
wire        inst_j;
wire        inst_jalr;     

wire        inst_lb;
wire        inst_lbu;
wire        inst_lh;
wire        inst_lhu;
wire        inst_lwl;
wire        inst_lwr;
wire        inst_sb;
wire        inst_sh;
wire        inst_swl;
wire        inst_swr;

wire        inst_eret;
wire        inst_mfc0;
wire        inst_mtc0;
wire        inst_syscall;
wire        inst_break;

wire        inst_tlbp;
wire        inst_tlbwi;
wire        inst_tlbr;

wire        pre_overflow;

wire        dst_is_r31;  
wire        dst_is_rt;   

wire [ 4:0] rf_raddr1;
wire [31:0] rf_rdata1;
wire [ 4:0] rf_raddr2;
wire [31:0] rf_rdata2;

wire ds_ex;
reg  ds_bd;
wire [4:0]ds_excode;
wire [4:0]c0_waddr;
wire refetch;

wire fs_bd;

//wire    [3:0] m_d; //mul or div

wire        rs_eq_rt;
wire        rs_gt_z;
wire        rs_ge_z;
wire        rs_lt_z;
wire        rs_le_z;  

assign br_bus       = {refetch,fs_bd,br_stall,br_taken,br_target};


assign ds_to_es_bus = { ds_refetch,//212
                        ds_tlb_r, //211
                        inst_tlbp,//210
                        inst_tlbwi,//209
                        inst_tlbr,//208
                        inst_lw, //207
                        inst_sw, //206
                        inst_lh,  //205
                        inst_lhu, //204
                        inst_sh,   //203
                        pre_overflow,  //202
                        fs_badvaddr,  //  201:170
                        c0_waddr, // 169:165
                        ds_bd,  //164
                        ds_ex,  //163
                        ds_excode, //162:158   
                        inst_mfc0,//157
                        inst_mtc0, //156
                        inst_eret,//155
                        inst_div, //154
                        inst_divu, //153
                        inst_mult, //152
                        inst_multu, //151
                        inst_mfhi, //150
                        inst_mflo, //149
                        inst_mthi,  //148
                        inst_mtlo,  //147
                        inst_lwl, //146
                        inst_lwr, //145
                        inst_swl,  //144
                        inst_swr,  //143
                        load_sign, // 142
                        load_byte,  //141
                        load_hw,    //140
                        store_byte,   //139
                        store_hw,      //138:138
                        alu_op      ,  //137:126
                        load_op     ,  //125:125
                        src1_is_sa  ,  //124:124
                        src1_is_pc  ,  //123:123
                        src1_is_0   ,  //122:122
                        src2_is_imm ,  //121:121
                        src2_is_0imm , //120:120
                        src2_is_8   ,  //119:119
                        gr_we       ,  //118:118
                        mem_we      ,  //117:117
                        dest        ,  //116:112
                        imm         ,  //111:96
                        rs_value    ,  //95 :64
                        rt_value    ,  //63 :32
                        ds_pc          //31 :0
                      };

always @(posedge clk) begin
    if(reset|flush)
        ds_bd <= 1'b0;
    else if((inst_beq | inst_bne | inst_bltz | inst_blez | inst_bgtz | inst_bgez | inst_bgezal | inst_bltzal | inst_jr | inst_jalr | inst_jal | inst_j) & ds_valid)
        ds_bd <= 1'b1;
    else if (ds_ready_go & es_allowin & ds_valid) begin
        ds_bd <=1'b0;
    end
    else
        ds_bd <= ds_bd;
end
//exception

assign ds_ex=(inst_syscall|inst_break|no_inst|interrupt)?1'b1:fs_ex & ds_valid;
assign fs_bd=(inst_beq | inst_bne | inst_bltz | inst_blez | inst_bgtz | inst_bgez | inst_bgezal | inst_bltzal | inst_jr | inst_jalr | inst_jal | inst_j) & ds_valid;
assign refetch = (inst_tlbr | inst_tlbwi) & ds_valid; 


assign ds_excode=(interrupt) ?  5'h00:
                 (fs_ex)     ?  fs_excode:
                 (no_inst)   ?  5'h0a:
                 (inst_syscall)?5'h08:
                 (inst_break)?  5'h09:
                                5'h00;

assign pre_overflow = (inst_add | inst_addi | inst_sub) & ds_valid;

assign  c0_waddr=rd;      

assign ds_ready_go    = ~(rs_valid & 
((es_load_op|es_inst_mfc0)&es_to_ds_valid&(es_dest==rs)
|ms_res_from_mem&ms_to_ds_valid&~ms_ready_go&(ms_dest==rs)
|ms_inst_mfc0&ms_to_ds_valid&(ms_dest==rs))
|rt_valid & ((es_load_op|es_inst_mfc0)&es_to_ds_valid&(es_dest==rt)
|ms_res_from_mem&ms_to_ds_valid&~ms_ready_go&(ms_dest==rt)
|ms_inst_mfc0&ms_to_ds_valid&(ms_dest==rt)));
/*assign ds_ready_go    = ~(rs_valid & (es_load_op&es_to_ds_valid&(es_dest==rs))|
                        rt_valid & (es_load_op&es_to_ds_valid&(es_dest==rt)));*/
assign ds_allowin     = !ds_valid || ds_ready_go && es_allowin;
assign ds_to_es_valid = ds_valid && ds_ready_go;
always @(posedge clk) begin
    if (reset|flush) begin
        ds_valid <= 1'b0;
    end
    else if (ds_allowin) begin
        ds_valid <= fs_to_ds_valid;
    end                             //bug1

    if (fs_to_ds_valid && ds_allowin) begin
        fs_to_ds_bus_r <= fs_to_ds_bus;
    end
end

assign op   = ds_inst[31:26];
assign rs   = ds_inst[25:21];
assign rt   = ds_inst[20:16];
assign rd   = ds_inst[15:11];
assign sa   = ds_inst[10: 6];
assign func = ds_inst[ 5: 0];
assign imm  = ds_inst[15: 0];
assign jidx = ds_inst[25: 0];

decoder_6_64 u_dec0(.in(op  ), .out(op_d  ));
decoder_6_64 u_dec1(.in(func), .out(func_d));
decoder_5_32 u_dec2(.in(rs  ), .out(rs_d  ));
decoder_5_32 u_dec3(.in(rt  ), .out(rt_d  ));
decoder_5_32 u_dec4(.in(rd  ), .out(rd_d  ));
decoder_5_32 u_dec5(.in(sa  ), .out(sa_d  ));

assign inst_addu   = op_d[6'h00] & func_d[6'h21] & sa_d[5'h00];
assign inst_add    = op_d[6'h00] & func_d[6'h20] & sa_d[5'h00];

assign inst_sub    = op_d[6'h00] & func_d[6'h22] & sa_d[5'h00];
assign inst_subu   = op_d[6'h00] & func_d[6'h23] & sa_d[5'h00];
assign inst_slt    = op_d[6'h00] & func_d[6'h2a] & sa_d[5'h00];
assign inst_slti   = op_d[6'h0a];
assign inst_sltu   = op_d[6'h00] & func_d[6'h2b] & sa_d[5'h00];
assign inst_sltiu  = op_d[6'h0b];
assign inst_and    = op_d[6'h00] & func_d[6'h24] & sa_d[5'h00];
assign inst_andi   = op_d[6'h0c];

assign inst_or     = op_d[6'h00] & func_d[6'h25] & sa_d[5'h00];
assign inst_ori    = op_d[6'h0d];

assign inst_xor    = op_d[6'h00] & func_d[6'h26] & sa_d[5'h00];
assign inst_xori   = op_d[6'h0e];

assign inst_nor    = op_d[6'h00] & func_d[6'h27] & sa_d[5'h00];
assign inst_sll    = op_d[6'h00] & func_d[6'h00] & rs_d[5'h00];
assign inst_sllv   = op_d[6'h00] & func_d[6'h04] & sa_d[5'h00];
   
assign inst_srl    = op_d[6'h00] & func_d[6'h02] & rs_d[5'h00];
assign inst_srlv   = op_d[6'h00] & func_d[6'h06] & sa_d[5'h00];

assign inst_sra    = op_d[6'h00] & func_d[6'h03] & rs_d[5'h00];
assign inst_srav   = op_d[6'h00] & func_d[6'h07] & sa_d[5'h00];

assign inst_addiu  = op_d[6'h09];

assign inst_addi   = op_d[6'h08];

assign inst_lui    = op_d[6'h0f] & rs_d[5'h00];

assign inst_mult    = op_d[6'h00] & func_d[6'h18] & sa_d[5'h00] & rd_d[5'h00];
assign inst_multu   = op_d[6'h00] & func_d[6'h19] & sa_d[5'h00] & rd_d[5'h00];
assign inst_div     = op_d[6'h00] & func_d[6'h1a] & sa_d[5'h00] & rd_d[5'h00];
assign inst_divu    = op_d[6'h00] & func_d[6'h1b] & sa_d[5'h00] & rd_d[5'h00];

assign inst_mfhi    = op_d[6'h00] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00] & func_d[6'h10];
assign inst_mflo    = op_d[6'h00] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00] & func_d[6'h12];

assign inst_mthi    = op_d[6'h00] & rd_d[5'h00] & rt_d[5'h00] & sa_d[5'h00] & func_d[6'h11];
assign inst_mtlo    = op_d[6'h00] & rd_d[5'h00] & rt_d[5'h00] & sa_d[5'h00] & func_d[6'h13];

assign inst_beq    = op_d[6'h04];
assign inst_bne    = op_d[6'h05];
assign inst_bgez   = op_d[6'h01] & rt_d[5'h01];
assign inst_bgtz   = op_d[6'h07] & rt_d[5'h00];
assign inst_blez   = op_d[6'h06] & rt_d[5'h00];
assign inst_bltz   = op_d[6'h01] & rt_d[5'h00];

assign inst_bltzal = op_d[6'h01] & rt_d[5'h10];
assign inst_bgezal = op_d[6'h01] & rt_d[5'h11];

assign inst_j      = op_d[6'h02];
assign inst_jal    = op_d[6'h03];
assign inst_jr     = op_d[6'h00] & func_d[6'h08] & rt_d[5'h00] & rd_d[5'h00] & sa_d[5'h00];
assign inst_jalr   = op_d[6'h00] & func_d[6'h09] & sa_d[5'h00] & rt_d[5'h00];

assign inst_lb     = op_d[6'h20];
assign inst_lbu    = op_d[6'h24];
assign inst_lh     = op_d[6'h21];
assign inst_lhu    = op_d[6'h25];
assign inst_lw     = op_d[6'h23];
assign inst_lwl    = op_d[6'h22];
assign inst_lwr    = op_d[6'h26];

assign inst_sb     = op_d[6'h28];
assign inst_sh     = op_d[6'h29];
assign inst_sw     = op_d[6'h2b];
assign inst_swl    = op_d[6'h2a];
assign inst_swr    = op_d[6'h2e];

assign inst_eret   = op_d[6'h10] & rs_d[6'h10] & rt_d[6'h00] & rd_d[6'h00] & sa_d[5'h00] & func_d[6'h18];
assign inst_mfc0   = op_d[6'h10] & rs_d[6'h00] & sa_d[5'h00] & 
(func_d[6'h00]|func_d[6'h01]|func_d[6'h02]|func_d[6'h03]|func_d[6'h04]|func_d[6'h05]|func_d[6'h06]|func_d[6'h07]);
assign inst_mtc0   = op_d[6'h10] & rs_d[6'h04] & sa_d[5'h00] & (func_d[6'h00]|func_d[6'h01]|func_d[6'h02]|func_d[6'h03]|func_d[6'h04]|func_d[6'h05]|func_d[6'h06]|func_d[6'h07]);
assign inst_syscall= op_d[6'h00] & func_d[6'h0c];
assign inst_break  = op_d[6'h00] & func_d[6'h0d];

assign inst_tlbp=op_d[6'h10] & rs_d[6'h10] & func_d [6'h08]; //[6'h10];
assign inst_tlbwi=op_d[6'h10] & rs_d[6'h10] & func_d[6'h02];
assign inst_tlbr=op_d[6'h10] & rs_d[6'h10] & func_d[6'h01];

assign no_inst =  ~inst_addu & ~inst_subu & ~inst_slt & ~inst_sltu & ~inst_and
                    & ~inst_or   & ~inst_xor  & ~inst_nor & ~inst_sll  & ~inst_srl
                    & ~inst_sra  & ~inst_addiu& ~inst_lui & ~inst_lw   & ~inst_sw 
                    & ~inst_beq  & ~inst_bne  & ~inst_jal & ~inst_jr   & ~inst_add
                    & ~inst_addi & ~inst_sub  & ~inst_slti& ~inst_sltiu& ~inst_andi
                    & ~inst_ori  & ~inst_xori & ~inst_sllv& ~inst_srav & ~inst_srlv
                    & ~inst_mult & ~inst_multu& ~inst_div & ~inst_divu & ~inst_mfhi
                    & ~inst_mflo & ~inst_mthi & ~inst_mtlo& ~inst_bgez & ~inst_bgtz
                    & ~inst_blez & ~inst_bltz & ~inst_j   & ~inst_bltzal& ~inst_bgezal
                    & ~inst_jalr & ~inst_lb   & ~inst_lbu & ~inst_lh   & ~inst_lhu
                    & ~inst_lwl  & ~inst_lwr  & ~inst_sb  & ~inst_sh   & ~inst_swl
                    & ~inst_swr  & ~inst_mfc0 & ~inst_mtc0& ~inst_syscall   & ~inst_eret & ~inst_break & ~inst_tlbp & ~inst_tlbr & ~inst_tlbwi;  




assign alu_op[ 0] = inst_addu | inst_addiu | inst_jal| inst_add| inst_addi | inst_jalr | inst_bgezal | inst_bltzal | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwl | inst_lwr | inst_sb | inst_sh | inst_sw | inst_swl | inst_swr | inst_mfc0 | inst_mtc0 | inst_tlbp | inst_tlbr | inst_tlbwi;
assign alu_op[ 1] = inst_subu | inst_sub;
assign alu_op[ 2] = inst_slt  | inst_slti;
assign alu_op[ 3] = inst_sltu | inst_sltiu;
assign alu_op[ 4] = inst_and  | inst_andi;
assign alu_op[ 5] = inst_nor;
assign alu_op[ 6] = inst_or   | inst_ori;
assign alu_op[ 7] = inst_xor  | inst_xori;
assign alu_op[ 8] = inst_sll | inst_sllv;
assign alu_op[ 9] = inst_srl | inst_srlv;
assign alu_op[10] = inst_sra | inst_srav;
assign alu_op[11] = inst_lui;

assign load_op    = inst_lw | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lwl | inst_lwr | inst_mfhi | inst_mflo;

assign src1_is_sa   = inst_sll   | inst_srl | inst_sra;
assign src1_is_pc   = inst_jal | inst_jalr | inst_bgezal | inst_bltzal;
assign src1_is_0    = inst_mfc0 | inst_mtc0;
assign src2_is_imm  = inst_addiu | inst_addi | inst_lui | inst_slti | inst_sltiu | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwl | inst_lwr | inst_sb | inst_sh | inst_sw | inst_swl | inst_swr;

assign src2_is_0imm = inst_andi | inst_ori | inst_xori;

assign src2_is_8    = inst_jal | inst_jalr | inst_bgezal | inst_bltzal;
assign res_from_mem = inst_lw;
assign dst_is_r31   = inst_jal | inst_bgezal | inst_bltzal;
assign dst_is_rt    = inst_addiu | inst_addi | inst_lui |  inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwl | inst_lwr | inst_slti | inst_sltiu | inst_andi | inst_ori | inst_xori | inst_mfc0;
assign gr_we        = ~inst_sw & ~inst_beq & ~inst_bne & ~inst_jr & ~inst_bltz & ~inst_blez & ~inst_bgtz & ~inst_bgez
                      & ~inst_div & ~inst_divu & ~inst_mult & ~inst_multu 
                      & ~inst_mtlo & ~inst_mthi
                      & ~inst_j 
                      & ~inst_sb & ~inst_sh & ~inst_swl & ~inst_swr
                      & ~inst_mtc0 & ~inst_eret & ~inst_syscall & ~inst_break; ///////////////

assign mem_we       =  inst_sb | inst_sh | inst_sw | inst_swl | inst_swr;

assign load_sign    =  inst_lb | inst_lh;
assign load_byte    =  inst_lb | inst_lbu;
assign load_hw      =  inst_lh | inst_lhu;
assign store_byte   =  inst_sb ;
assign store_hw     =  inst_sh ;

assign rs_valid     = (inst_addu | inst_add | inst_addiu | inst_addi | inst_subu | inst_sub | 
                         inst_beq | inst_bne |inst_jr | inst_slt | inst_sltu | inst_slti | inst_sltiu
                       | inst_and | inst_or | inst_nor | inst_xor | inst_andi | inst_ori | inst_xori
                       | inst_sllv | inst_srlv | inst_srav
                       | inst_mult | inst_multu | inst_div| inst_divu 
                       | inst_mthi | inst_mtlo 
                       | inst_bgez | inst_bgtz | inst_blez | inst_bltz
                       | inst_bgezal | inst_bltzal
                       | inst_jalr 
                       | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwl | inst_lwr | inst_sb | inst_sh | inst_sw | inst_swl | inst_swr) &!(rs==5'b0);
assign rt_valid     = (inst_addu | inst_add | inst_subu | inst_sub
                        | inst_sllv | inst_srlv | inst_srav | inst_beq | inst_bne 
                        | inst_slt | inst_sltu | inst_sll | inst_srl | inst_sra 
                        | inst_and | inst_or | inst_nor | inst_xor 
                        | inst_mult | inst_multu | inst_div | inst_divu 
                        | inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwl | inst_lwr | inst_sb | inst_sh | inst_sw | inst_swl | inst_swr
                        | inst_mtc0) &!(rt==5'b0);


assign dest         = dst_is_r31 ? 5'd31 :
                      dst_is_rt  ? rt    : 
                                   rd;

assign rf_raddr1 = rs;
assign rf_raddr2 = rt;

//assign  m_d = {inst_div,inst_divu, inst_mult,inst_multu };
regfile u_regfile(
    .clk    (clk      ),
    .raddr1 (rf_raddr1),
    .rdata1 (rf_rdata1),
    .raddr2 (rf_raddr2),
    .rdata2 (rf_rdata2),
    .we     (rf_we    ),
    .waddr  (rf_waddr ),
    .wdata  (rf_wdata )
    );

assign ms_rf_we_ex={{8{ms_rf_we[3]}},{8{ms_rf_we[2]}},{8{ms_rf_we[1]}},{8{ms_rf_we[0]}}};
assign rf_we_ex={{8{rf_we[3]}},{8{rf_we[2]}},{8{rf_we[1]}},{8{rf_we[0]}}};
always @(*) begin
    if(rs_valid)begin
        if(es_to_ds_valid&(es_dest==rs))begin
            rs_value = es_alu_result;
        end
        else if(ms_to_ds_valid&ms_dest==rs)begin
            if(rf_waddr==rs)begin
                rs_value = (ms_final_result&ms_rf_we_ex)|(((rf_wdata&rf_we_ex)|(rf_rdata1&~rf_we_ex))&~ms_rf_we_ex);
            end
            else begin
                rs_value = (ms_final_result&ms_rf_we_ex)|(rf_rdata1&~ms_rf_we_ex);
            end
        end
        else if(rf_waddr==rs)begin
            rs_value = (rf_wdata&rf_we_ex)|(rf_rdata1&~rf_we_ex);
        end
        else begin
        rs_value = rf_rdata1;
        end
    end
    else begin
        rs_value = rf_rdata1;
    end
end
always @(*) begin
    if(rt_valid)begin
        if(es_to_ds_valid&(es_dest==rt))begin
            rt_value = es_alu_result;
        end
        else if(ms_to_ds_valid&ms_dest==rt)begin
            if(rf_waddr==rt)begin
                rt_value = (ms_final_result&ms_rf_we_ex)|(((rf_wdata&rf_we_ex)|(rf_rdata2&~rf_we_ex))&~ms_rf_we_ex);
            end
            else begin
                rt_value = (ms_final_result&ms_rf_we_ex)|(rf_rdata2&~ms_rf_we_ex);
            end
        end
        else if(rf_waddr==rt)begin
            rt_value = (rf_wdata&rf_we_ex)|(rf_rdata2&~rf_we_ex);
        end
        else begin
        rt_value = rf_rdata2;
        end
    end
    else begin
        rt_value = rf_rdata2;
    end
end


assign rs_eq_rt = (rs_value == rt_value);
assign rs_gt_z = (~rs_value[31] && rs_value!=32'b0);
assign rs_ge_z = ~rs_value[31];
assign rs_lt_z = (rs_value[31]);
assign rs_le_z = (rs_value[31] || rs_value == 32'b0);


assign br_stall = ~ds_ready_go &fs_bd;
assign br_taken = (   inst_beq  &&  rs_eq_rt
                   || inst_bne  && !rs_eq_rt
                   || inst_bgez && rs_ge_z
                   || inst_bgtz && rs_gt_z
                   || inst_blez && rs_le_z
                   || inst_bltz && rs_lt_z
                   || inst_bltzal && rs_lt_z
                   || inst_bgezal && rs_ge_z
                   || inst_j
                   || inst_jalr
                   || inst_jal
                   || inst_jr
                  ) && ds_valid;
assign ds_pc_add_4=ds_pc+4;
assign br_target = (inst_beq || inst_bne 
                 || inst_bltz || inst_blez || inst_bgtz || inst_bgez
                 || inst_bgezal || inst_bltzal) ? (ds_pc_add_4 + {{14{imm[15]}}, imm[15:0], 2'b0}) :
                   (inst_jr || inst_jalr)              ? rs_value :
                  /*inst_jal   inst_j*/              {ds_pc_add_4[31:28], jidx[25:0], 2'b0};

endmodule
